package utils;

import api.APICallRateMonitor;
import api.APICallTypes;
import api.Market;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * User: Darren
 * Date: 28/10/12
 * Time: 10:05 AM
 */
public class ConsoleDisplay implements Display {
    private StringBuilder sb = new StringBuilder();
    private BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));

    private StringBuilder getStringBuilder() {
        return sb.delete(0, sb.length());
    }

    private void printlnError(String value) {
        System.err.println(value);
        System.out.flush();
    }

    private void print(String value) {
        System.out.print(value);
        System.out.flush();
    }

    private void println(String value) {
        System.out.println(value);
        System.out.flush();
    }

    private static void println() {
        System.out.println();
        System.out.flush();
    }

    private String readLine() throws IOException {
        return consoleReader.readLine();
    }

    @Override
    public int getIntAnswer(String question) throws IOException {
        while (true) {
            String intAsString = getStringAnswer(question);
            try {
                return Integer.parseInt(intAsString);
            } catch (NumberFormatException e) {
                printlnError("A number was not entered.");
            }
        }
    }

    @Override
    public String getStringAnswer(String question) throws IOException {
        print(question);
        return readLine();
    }

    @Override
    public void displayTotal(APICallRateMonitor apiCallRateMonitor, APICallTypes type) {
        System.out.print(type.getName() + " total: " + apiCallRateMonitor.getTotal(type) + " ");
    }

    @Override
    public void displayCallPerSecond(APICallRateMonitor apiCallRateMonitor, APICallTypes type) {
        int[] apiCallPerSecond = apiCallRateMonitor.getCallPerSecond(type);
        int nIntervals = apiCallPerSecond.length;
        for (int i = 0; i < nIntervals; ++i) {
            System.out.print(apiCallPerSecond[i]);
            if (i < nIntervals - 1) {
                System.out.print(", ");
            }
        }
    }

    @Override
    public void displayTotalAndCallPerSecond(APICallRateMonitor apiCallRateMonitor, APICallTypes type) {
        displayTotal(apiCallRateMonitor, type);
        displayCallPerSecond(apiCallRateMonitor, type);
        println();
    }

    private void println(String[] strings) {
        for (String str: strings) {
            println(str);
        }
    }

    @Override
    public int getChoiceAnswer(String question, String[] possibilities, int minValidAnswer,
                               int maxValidAnswer) throws IOException {
        int selection;
        do {
            println(question);
            println(possibilities);
            selection = getIntAnswer("Selection: ");
        } while (selection < minValidAnswer || selection > maxValidAnswer);
        return selection;
    }

    @Override
    public int getChoiceAnswer(String question, String possibilitySetAHeadings, String[] possibilitySetA,
                               String possibilitySetBHeadings, String[] possibilitySetB,
                               int minValidAnswer, int maxValidAnswer) throws IOException {
        int selection;
        do {
            println(question);
            println(possibilitySetAHeadings);
            println(possibilitySetA);
            println(possibilitySetBHeadings);
            println(possibilitySetB);
            selection = getIntAnswer("Selection: ");
        } while (selection < minValidAnswer  || selection > maxValidAnswer);
        return selection;
    }

    @Override
    public int getChoiceAnswer(String question, String possibilitySetHeadings, String[] possibilitySet,
                              int minValidAnswer, int maxValidAnswer) throws IOException {
        int selection;
        do {
            println(question);
            println(possibilitySetHeadings);
            println(possibilitySet);
            selection = getIntAnswer("Selection: ");
        } while (selection < minValidAnswer || selection > maxValidAnswer);
        return selection;
    }

    @Override
    public void displayMarketInfo(Market market) {
        println(getStringBuilder().append("Market: ").append(market.getMarketName()).append(" (")
                .append(market.getMarketId()).append(") on the ")
                .append(market.getExchangeName()).append(" exchange:").toString());
        println(getStringBuilder().append("    Start time: ").append(market.getStartTime()).toString());
        println(getStringBuilder().append("        Status: ").append(market.getStatus()).toString());
        println(getStringBuilder().append("      Location: ").append(market.getCountry()).toString());
    }

    @Override
    public void displayMarketRunners(Market market) {
        println("Runners: ");
        for (Object obj: market.getRunners()) {
            Market.Runner runner;
            if (obj instanceof Market.Runner) {
                runner = (Market.Runner)obj;
            } else {
                throw new RuntimeException("Market Runners of unexpected type");
            }
            String bestLay = "";
            if (runner.getLayPricesSize() > 0) {
                Market.Price bestLayPrice = runner.getLayPrice(0);
                bestLay = String.format("%,10.2f %s @ %,6.2f", bestLayPrice.getAmountAvailable(), market.getCurrency(),
                        bestLayPrice.getPrice());
            }
            String bestBack = "";
            if (runner.getBackPricesSize() > 0) {
                Market.Price bestBackPrice = runner.getBackPrice(0);
                bestBack = String.format("%,10.2f %s @ %,6.2f", bestBackPrice.getAmountAvailable(),
                        market.getCurrency(), bestBackPrice.getPrice());
            }
            println(String.format(
                    "%20s (%6d): Matched Amount: %,10.2f, Last Matched: %,6.2f, Best Back %s, Best Lay:%s",
                    runner.getName(), runner.getSelectionId(), runner.getTotalAmountMatched(),
                    runner.getLastPriceMatched(), bestBack, bestLay));
        }
    }
}
